/**
 * *******************************************
 * user: zmq
 * describe:
 * created:
 * date: 2021/8/19
 * *******************************************
 */

import {MAX_UID, SEX} from "../consts/consts";
import AccountDao from "../dao/mysqlDao/accountDao";
import {logger} from "../util/logger";
import UserDao from "../dao/mysqlDao/userDao";
import {ICreateRole} from "../consts/interface";
import {User} from "../domain/entity/user";
import Utils from "../util/utils";
import {MessagePack} from "../util/messagePack";
import {ERRORCODE} from "../util/errorCode";


/**
 * 单例模式，内存唯一指向
 */
class AreaService {

    private static _instance: AreaService = undefined;          // 声明一个 GateService 对象
    private serverId: number = 0;                                // 服务器id
    private usersMap: any = {};                                  // 玩家容器
    private maxUid: number = 0;                                  // 当前服务器最大角色uid
    private isStartUp: boolean = false;                          // 服务器是否启动
    private nicknameArr: string[] = [];                          // 本区已使用的昵称数组
    private constructor() {

    };

    /**
     * 返回一个唯一实例
     * @returns {AreaService}
     */
    public static getInstance(): AreaService {

        if (this._instance === undefined) {
            this._instance = new AreaService();
        }
        return this._instance;
    };


    /**
     * 初始化area管理单例
     * @param serverId
     */
    public init(serverId) {

        this.serverId = serverId;
        this.usersMap = {};
        this.isStartUp = false;

    }

    /**
     * 启动游戏处理
     */
    public async startup() {

        this.isStartUp = true;   // 服务器是否启动

        // 获取已经注册的角色昵称
        let nicknameData = await UserDao.getAllNickname();
        if(!nicknameData){
            logger.error(`get server nicknameArr failed!`);
        }
        if (nicknameData && nicknameData.length > 0) {
            for(let i in nicknameData){
                if(nicknameData.hasOwnProperty(i)){
                    this.nicknameArr.push(nicknameData[i].nickname);
                }
            }
        }

        // 获取已经注册的角色昵称
        let err1 = await UserDao.getGmMap();
        console.log("----------------> err1 " ,err1);
    }


    /**
     * 创建角色 逻辑处理
     * @param roleInfo
     * @returns {Promise<any>}
     */
    public async createRole(roleInfo: any) {

        let self = this;
        let account: string = roleInfo.account;
        let nickname: string = roleInfo.nickname;
        let sex = roleInfo.sex;

        // 服务器维护中
        if (!this.isStartUp) {
            return MessagePack.failResult(ERRORCODE.AREA_SERVER_IS_MAINTAIN);
        }

        // 服务器注册数量角色 大于 设定好的最大值
        if (self.maxUid > MAX_UID) {
            return MessagePack.failResult(ERRORCODE.AREA_ALREADY_ROLE_LIMIT_NUM);
        }

        // 客户端发送过来的性别为空或者性别数据不对，自动随机一个
        let sexArr = [SEX.girl, SEX.boy];
        if (sex === undefined || sexArr.indexOf(sex) === -1) {
            sex = Utils.rand(SEX.girl, SEX.boy);
        }

        // 由服务器分配昵称
        if (nickname === undefined) {
            // nickname = self.randomNickname(sex);
            nickname = "sdsd";
        } else { // 客户端有发昵称的

            let checkErr = Utils.checkNickname(nickname, self.nicknameArr);  // 检查昵称的合法性
            if (checkErr) {
                return MessagePack.failResult(ERRORCODE.AREA_NICKNAME_IS_ERR);
            }
        }

        // 获取该账号是否存在
        let accountData = await AccountDao.getAccount(account);
        if (!accountData) {  // 查询账号信息错误抛出
            return MessagePack.failResult(ERRORCODE.MYSQL_GET_ERROR);
        }
        if (accountData.length === 0) { // 账号数据不存在
            return MessagePack.failResult(ERRORCODE.GATE_ACCOUNT_NOT_EXIST);
        }


        // 获取该账号是否已经创建角色
        let userData = await UserDao.getUsersByAccount(account);
        if (!userData) {
            return MessagePack.failResult(ERRORCODE.MYSQL_GET_ERROR);
        }
        // 检查是否重复创建角色
        if (userData && userData.length > 0) {
            return MessagePack.failResult(ERRORCODE.AREA_REPEAT_CREATE_ROLE);
        }


        let headPng = (sex === SEX.boy ? 0 : 1);// 女0男1
        // 创建角色信息赋值
        let createRuleInfo: ICreateRole = {
            uid: this.maxUid,
            account: account,
            nickname: nickname,
            sex: sex,
            level: 1,
            headPng: headPng
        };

        // 创建角色
        let addUserData = await UserDao.addUser(createRuleInfo);
        if (!addUserData) {
            logger.info("addUserErr --> ", addUserData);
            return MessagePack.failResult(ERRORCODE.MYSQL_ADD_ERROR);
        }

        /***********  创建角色后需要初始化的内容  各个模块的表 ***********/

        this.maxUid++;                  // 当前最大玩家uid自增
        self.nicknameArr.push(nickname); // 创建成功，保存昵称


        // 创建成功后 只返回玩家的uid 客户端再进行登录操作
        return {uid: createRuleInfo.uid};
    }

    /**
     * 玩家登录处理
     * @param msg
     * @returns {any}
     */
    public login(msg: any) {

        let userInfo = msg.userInfo;
        let uid = userInfo.uid;

        // 服务器维护中
        if (!this.isStartUp) {
            return MessagePack.failResult(ERRORCODE.AREA_SERVER_IS_MAINTAIN);
        }

        // 从内存中拉取玩家数据
        let user = this.getUserByUid(uid);
        // 内存有数据,执行登录操作
        if (user) {
            this.afterLogin(user);
            return MessagePack.successResult(user.getUserData());
        }

        let userData = {
            uid: userInfo.uid,
            account: userInfo.account,
            nickname: userInfo.nickname,
            sex: userInfo.sex,
            level: userInfo.level,
            headPng: userInfo.headPng,
            createTime: userInfo.createTime,
            loginTime: userInfo.loginTime,
            IP: msg.IP
        };
        // 创建玩家实例，并插入内存,执行登录操作
        user = new User(userData);
        this.setUserMapData(uid, user);
        this.afterLogin(user);

        return MessagePack.successResult(userData);
    }


    /**
     * 登陆后处理函数
     * @param user
     */
    private  afterLogin(user: any) {

        return;

    }


    /**
     * 获取玩家容器
     */
    public getUserMap(): any {

        return this.usersMap;
    }

    /**
     * 根据uid来获取玩家信息
     * @param {number} uid
     * @returns {any}
     */
    public getUserByUid(uid: number) {

        let self = this;
        return self.usersMap[uid];
    }

    /**
     * 设置玩家数据
     * @param uid
     * @param user
     */
    public setUserMapData(uid: number, user: any): void {

        let self = this;
        self.usersMap[uid] = user;
    }
}

// 抛出接口
export default AreaService.getInstance();